{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Polygon Simplification"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Basic simplification:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import skgeom as sg\n",
    "poly = sg.random_polygon(30, seed=3)\n",
    "poly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`simplify` tries to remove a given portion of the vertices without changing the topology:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sg.draw.draw(poly, facecolor=\"white\", alpha=0.4)\n",
    "res = sg.simplify(poly, 0.5)  # try to remove 50% of the vertices\n",
    "sg.draw.draw(res, alpha=0.85)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sg.draw.draw(poly, facecolor=\"red\")\n",
    "sg.simplify(poly, 0.2)  # try to remove 80% of the vertices"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`simplify` works on `Polygon`, `PolygonWithHoles` and `PolygonSet`. You can also apply `simplify` on lists of polygons."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poly_set = sg.PolygonSet([sg.random_polygon(10, seed=4), sg.random_polygon(40, seed=3)])\n",
    "sg.draw.draw(poly_set, facecolor=\"red\")\n",
    "sg.simplify(poly_set, 0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simplification Modes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`simplify` currently supports three modes:\n",
    "* \"ratio\": try to reduce number of vertices to a given ratio of the original count\n",
    "* \"count\": try to reduce number of vertices to an absolute number\n",
    "* \"sqeuclidean\": try to reduce number of vertices until the error (squared euclidean distance) becomes too big"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sg.draw.draw(poly, facecolor=\"red\")\n",
    "sg.simplify(poly, 0.5, \"ratio\")  # try to remove 50% of vertices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sg.draw.draw(poly, facecolor=\"red\")\n",
    "sg.simplify(poly, 0.2, \"sqeuclidean\")  # try to remove while err (sq. distance) < 0.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In general, all modes are targets that might not be met:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(poly.coords)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(sg.simplify(poly, 0.5, \"ratio\").coords)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(sg.simplify(poly, 0.25, \"ratio\").coords)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "len(sg.simplify(poly, 5, \"count\").coords)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simplification and Topology"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, `simplify` tries to preserve topology."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from skgeom import boolean_set\n",
    "poly = boolean_set.difference(\n",
    "    sg.random_polygon(20, size=4, seed=4234),\n",
    "    sg.random_polygon(20, size=1, seed=8421))[0]\n",
    "poly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By preserving topology, features like holes will not get lost:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poly2 = sg. simplify(poly, 0.2, \"ratio\")  # try to remove 50% of vertices\n",
    "poly2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Turning off `preserve_topology` is much faster, but might destroy structural features:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poly2 = sg. simplify(poly, 0.2, \"ratio\", preserve_topology=False)\n",
    "poly2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`preserve_topology` implies limits to how much simplifcation can happen:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poly2 = sg. simplify(poly, 1, \"count\")\n",
    "poly2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poly2 = sg.simplify(poly, 1, \"count\", preserve_topology=False)\n",
    "poly2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### More Topology Examples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nested = [sg.random_polygon(15, shape=\"circle\", size=r ** 3, seed=r * 5) for r in range(3, 10)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def draw_nested(nested):\n",
    "    for p in reversed(nested):\n",
    "        sg.draw.draw(p)\n",
    "        \n",
    "draw_nested(nested)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "draw_nested(sg.simplify(nested, 0.3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "with defaults, forms have been simplified while preserving topology:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def n_vertices(nested):\n",
    "    return sum(len(p) for p in nested)\n",
    "\n",
    "(n_vertices(nested), n_vertices([p.outer_boundary() for p in sg.simplify(nested, 0.3)]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "same call without preserving topology:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "draw_nested(sg.simplify(nested, 0.3, preserve_topology=False))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
